home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 9
/
Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO
/
009a
/
newtk200.zip
/
NEWTDLL.CPP
next >
Wrap
C/C++ Source or Header
|
1993-03-11
|
10KB
|
501 lines
// @(#) %M% V%I% %H%
//
// File name
// -------------
// NEWTDLL.CPP
//
// (c) Cavendish Software Ltd 1991, 1992
//
// Document References
// -------------------
// This is a general purpose module, and as such has no document references
//
// File Description
// ----------------
// Newtrack v2.0/Windows. DLL Section of NewTrack, a new/delete and
// open/close tracking and verification system.
//
// HEADER FILES
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <newtrack.hpp>
// ENUMERATED TYPES - Errors
enum TRK_ERROR
{
TKE_OK = 0, // No error
TKE_UNDERRUN, // Pointer Underrun
TKE_OVERRUN, // Pointer Overrun
TKE_BADPTR, // Invalid pointer
TKE_NULLPTR, // NULL Pointer
TKE_NOMEMORY, // Out of memory
TKE_NEWLEFTOVER // Unfreed allocations
};
// TYPE DEFINITIONS & CLASSES
// Block Structure. Used to track an allocation
struct NT_BLOCK
{
TRK_CALLER caller;
NT_PTR ptr;
NT_SIZE size;
NT_BLOCK *next;
NT_BLOCK *prev;
NT_BLOCK(NT_PTR _ptr, NT_SIZE _size, TRK_CALLER _caller) :
ptr(_ptr),
size(_size),
caller(_caller),
next(0),
prev(0)
{
// Nothing
}
~NT_BLOCK(void)
{ ptr = 0; size = 0; next = 0; prev = 0; caller = 0; }
};
// Task Structure. Contains info for a task
struct NT_TASK
{
HTASK taskid;
int tracking;
TRK_ERROR error;
NT_BLOCK *blocks;
unsigned long nallocs;
NT_TASK *next;
NT_TASK *prev;
NT_TASK(int _tracking = 0) :
tracking(_tracking),
error(TKE_OK),
blocks(0),
nallocs(0),
next(0),
prev(0)
{
taskid = GetCurrentTask();
}
// Adds a block to the list
void AddBlock(NT_PTR p, NT_SIZE size, TRK_CALLER caller);
// Removes a block from the list
void ExtractBlock(NT_BLOCK *blk);
// Validates a pointer, calling the error handler if invalid
NT_BLOCK *ValidPtr(NT_PTR p);
// Error handler
void HandleError(TRK_ERROR err, unsigned long count = 0);
};
// GLOBAL VARIABLES -- Error Messages
static char *errmsgs[]=
{
"No Error!",
"Pointer Underrun",
"Pointer Overrun",
"Invalid Pointer Passed to Delete",
"NULL Pointer Allocation",
"Out of Memory",
"%lu Unfreed Memory Allocations"
};
// GLOBAL VARIABLES
static NT_TASK *tasklist = 0;
// GLOBAL VARIABLES -- EXTERNALS
#ifndef __DLL__
extern int __newtrack;
#endif
// FUNCTION PROTOTYPES
NT_TASK *NT_FindTask(void);
void _hmemset(NT_PTR p, int c, NT_SIZE n);
void _hmemcpy(NT_PTR dest, NT_PTR src, NT_SIZE n);
int _hmemcmp(NT_PTR s1, NT_PTR s2, NT_SIZE n);
//
//
// Methods for Class: NT_TASK
//
//
void NT_TASK::AddBlock(NT_PTR p, NT_SIZE size, TRK_CALLER caller)
{
// Turn off NewTrack tracking to prevent loopback
#ifndef __DLL__
__newtrack = 0;
#endif
// Create a new block
NT_BLOCK *blk = new NT_BLOCK(p, size, caller);
// Turn NewTrack tracking back on
#ifndef __DLL__
__newtrack = 1;
#endif
// If there is already a list...
if (blocks)
{
// Find the last in the list
NT_BLOCK *b2 = blocks;
for (; b2->next; b2 = b2->next)
;
// Tack the new block onto the end
b2->next = blk;
blk->prev = b2;
}
else
// No list yet, so start it off...
blocks = blk;
// Increase count of allocations
nallocs++;
}
void NT_TASK::ExtractBlock(NT_BLOCK *blk)
{
// Point the previous block around
if (blk->prev)
blk->prev->next = blk->next;
else
blocks = blk->next;
// Point the next block around
if (blk->next)
blk->next->prev = blk->prev;
// Decrease the number of allocations
nallocs--;
}
// Validates the pointer as being allocated via NewTrack
NT_BLOCK *NT_TASK::ValidPtr(NT_PTR p)
{
NT_BLOCK *blk = blocks;
// See if we can find a match for the pointer
for (; blk; blk = blk->next)
if (blk->ptr == p)
break;
// If no match...
if (!blk)
{
// Tell the user
HandleError(TKE_BADPTR);
return 0;
}
// Check the pre-text is still there
if (_hmemcmp(p, (NT_PTR) NT_PRE_TEXT, NT_PRE_SIZE) != 0)
{
// Tell the user
HandleError(TKE_UNDERRUN);
return 0;
}
// Check the post-text is still there
if (_hmemcmp(p + blk->size - NT_POST_SIZE, (NT_PTR) NT_POST_TEXT,
NT_POST_SIZE) != 0)
{
// Tell the user
HandleError(TKE_OVERRUN);
return 0;
}
// The pointer is valid....return the block
return blk;
}
// Tells the user abouts the error, with the option to terminate app.
void NT_TASK::HandleError(TRK_ERROR err, unsigned long count)
{
char tmps[500];
sprintf(tmps, errmsgs[err], count);
strcat(tmps, " - Continue?");
// Tell the user
int ret = MessageBox(0, tmps, "NewTrack Error", MB_SYSTEMMODAL |
MB_ICONSTOP | MB_OKCANCEL);
// Abort the app if requested
if (ret != IDOK)
abort();
// Break into the debugger
asm int 3;
}
// FUNCTIONS
// Initialises NewTrack tracking for the current task
void _far _pascal NT_Initialise(void)
{
// Allocate Task info
NT_TASK *task = new NT_TASK(1);
// If this is the first task to use NewTrack, start the list off
if (!tasklist)
tasklist = task;
else
{
NT_TASK *last;
// Find the last task in the list
for (last = tasklist; last->next; last = last->next)
; // Nothing
// Add a new one onto the end
last->next = task;
task->prev = last;
}
}
// Terminates NewTrack tracking for the current task
unsigned long _far _pascal NT_Terminate(void)
{
unsigned long nallocs;
NT_BLOCK **blist = 0;
NT_TASK *task = NT_FindTask();
// If there are any unfreed pointers (for this task)
if ((nallocs = task->nallocs) > 0)
{
unsigned blsize;
// Make sure we can handle the number
if (nallocs > 0xfffe)
blsize = 0xfffe;
else
blsize = (unsigned) nallocs;
// Tell the user
task->HandleError(TKE_NEWLEFTOVER, nallocs);
// Create a shorthand array of unfreed blocks
blist = new NT_BLOCK *[blsize + 1];
// If we made it...
if (blist)
{
unsigned i;
NT_BLOCK *blk = task->blocks;
// Make up the list of unfreed blocks for this task
for (i = 0; blk; blk = blk->next, i++)
blist[i] = blk;
// Terminate the list
blist[i] = 0;
}
}
// If there are any unfreed allocs, break into the debugger
if (blist)
{
asm int 3
// Free up the shorthand list
if (blist)
delete blist;
}
// Point the previous task around us
if (task->prev)
task->prev->next = task->next;
else
tasklist = task->next;
// Point the next task around us
if (task->next)
task->next->prev = task->prev;
// Return number of allocations left over
return nallocs;
}
// Transforms a pointer p into a NewTrack pointer by adding a
// header & trailer.
NT_PTR _far _pascal NT_New(void far *_p, NT_SIZE size, TRK_CALLER caller)
{
NT_TASK *task = NT_FindTask();
NT_PTR p = (NT_PTR) _p;
// If tracking is turned off, drop out straight away
if (!task || !task->tracking)
return p;
// If we ran out of memory, tell the user
if (!p)
{
task->HandleError(TKE_NOMEMORY);
return 0;
}
// Set the pre-text and post-text, and initialise the rest
_hmemcpy(p, (NT_PTR) NT_PRE_TEXT, NT_PRE_SIZE);
_hmemcpy(p + size - NT_POST_SIZE, (NT_PTR) NT_POST_TEXT, NT_POST_SIZE);
_hmemset(p + NT_PRE_SIZE, NT_NEWFILL, size - NT_PRE_SIZE - NT_POST_SIZE);
// Add the block to the tasks' list
task->AddBlock(p, size, caller);
// Return the pointer *after* our pre-text
return p + NT_PRE_SIZE;
}
// Transforms a NewTrack pointer into an oridinary pointer by
// removing the header.
void far * _far _pascal NT_Delete(NT_PTR p)
{
NT_TASK *task = NT_FindTask();
NT_BLOCK *blk;
// Is there any tracking running at all?
if (!task || !task->tracking)
return p;
// Restore the pointer to that returned by malloc()
p -= NT_PRE_SIZE;
// If we have a valid pointer
if ((blk = task->ValidPtr(p)) != 0)
{
// Extract block from the list
task->ExtractBlock(blk);
// Fill in the block with known "garbage"
_hmemset(p, NT_DELFILL, blk->size);
// Turn off NewTrack tracking to prevent loopback
#ifndef __DLL__
__newtrack = 0;
#endif
// Delete the block
delete blk;
// Turn NewTrack tracking back on
#ifndef __DLL__
__newtrack = 1;
#endif
}
else
return 0;
// Return the pointer to be freed by the real task
return (void far *)p;
};
// Finds the NT_TASK structure for the current task
NT_TASK *NT_FindTask(void)
{
NT_TASK *task = tasklist;
// Find the NT_TASK for the current task
for (; task; task = task->next)
if (task->taskid == GetCurrentTask())
break;
// Return the found task
return task;
}
// Returns the number of allocations
unsigned long NT_EXPORT _far _pascal NT_NAllocs(void)
{
NT_TASK *task = NT_FindTask();
return (task) ? task->nallocs : 0;
}
// Returns the real size to allocate; called by new() so that the task can allocate
NT_SIZE _far _pascal NT_NewSize(unsigned long size)
{
return size + NT_PRE_SIZE + NT_POST_SIZE;
}
//
//
// Helper functions
//
//
// Huge memset() - sets n bytes of data to c
void _hmemset(NT_PTR p, int c, NT_SIZE n)
{
for (; n; p++, n--)
*p = c;
}
// Huge memcpy() - copies n bytes from src to dest
void _hmemcpy(NT_PTR dest, NT_PTR src, NT_SIZE n)
{
for (; n; n--, dest++, src++)
*dest = *src;
}
// Huge memcmp() - compares n bytes of s1 with s2
int _hmemcmp(NT_PTR s1, NT_PTR s2, NT_SIZE n)
{
for (; n && *s1 == *s2; n--, s1++, s2++)
;
return (n) ? ((int)(s1 - s2)) : 0;
}
//
//
// DLL specific Functions
//
//
#ifdef __DLL__
#pragma argsused
int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSegment, WORD wHeapSize, LPSTR lpszCmdLine)
{
if (wHeapSize != 0)
UnlockData(0);
return (1);
}
#pragma argsused
int FAR PASCAL WEP(int bSystemExit)
{
return (1);
}
#endif